package com.fzk.blog.settings.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fzk.blog.bean.*;
import com.fzk.blog.bean.vo.BlogInfo;
import com.fzk.blog.blog.service.IRedisService;
import com.fzk.blog.exception.MyException;
import com.fzk.blog.mapper.*;
import com.fzk.blog.settings.service.IBlogService;
import com.fzk.blog.utils.MyDateTimeUtil;
import com.fzk.blog.utils.MyJsonUtil;
import com.fzk.blog.utils.ResponseResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author fzk
 * @date 2021-08-21 10:45
 */
@Service
public class BlogService implements IBlogService {
    @Resource
    private BlogMapper blogMapper;
    @Resource
    private TagMapper tagMapper;
    @Resource
    private TypeMapper typeMapper;
    @Resource
    private BlogTagReferenceMapper blogTagReferenceMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private IRedisService redisService;

    @Override
    @Transactional//开事务
    public void insertBlog(Blog blog, String[] tag, int loginId) {
        // 1.完善插入数据
        blog.setCreateBy(loginId);
        blog.setEditBy(loginId);
        blog.setViewTimes(0);
        if (blog.getPublished())//如果发布，则设置发布日期
            blog.setPublishDate(MyDateTimeUtil.getNowDate());
        blog.setFlag(0);


        // 2.插入blog（这里就不去检查标题是否重复了）
        // 2.1检查typeId
        Type type = typeMapper.selectById(blog.getTypeId());
        if (type == null)
            throw new MyException(400, "参数错误：type_id不存在：" + blog.getTypeId());
        // 2.2插入
        int insert = blogMapper.insert(blog);
        if (insert != 1)
            throw new MyException(500, "插入失败");

        // 3.插入标签和博客对于关系
        // 3.1 检查tag的id是否正确
        List<Integer> tagList = new ArrayList<>();
        for (String t : tag)
            tagList.add(Integer.parseInt(t));

        List<Tag> tags = tagMapper.selectBatchIds(tagList);//这里的tagList不能为空的哦，否则报错
        if (tags.size() != tag.length)
            throw new MyException(400, "参数错误，tag存在非法id：" + Arrays.toString(tag));
        // 3.2 准备插入数据
        for (int tagId : tagList) {
            BlogTagReference reference = new BlogTagReference();
            reference.setBlogId(blog.getId());
            reference.setTagId(tagId);
            reference.setCreateBy(loginId);
            reference.setEditBy(loginId);
            reference.setFlag(0);
            // 插入
            int i = blogTagReferenceMapper.insert(reference);
            if (i != 1)
                throw new MyException(500, "插入blog和tag的关联失败");
        }
        // 4.删除redis 的 newBlogList
        redisService.delete("newBlogList");
    }

    @Override
    @Transactional//开事务
    public void updateBlog(Blog blog, String[] tag, int loginId) {
        // 1.完善修改数据
        BlogInfo oldBlog = blogMapper.getBlogInfoById(blog.getId());
        blog.setEditBy(loginId);
        if (!oldBlog.getPublished() && blog.getPublished()) {
            // 重新发布的需要重置发布日期
            blog.setPublishDate(MyDateTimeUtil.getNowDate());
        }

        // 2.修改blog（这里就不去检查标题是否重复了）
        // 2.0 检查loginId和create_by是否符合
        int createBy = blogMapper.getCreateById(blog.getId());
        if (createBy != loginId)
            throw new MyException(400, "抱歉：您不是此博客的发布者，无权修改");
        // 2.1检查typeId
        Type type = typeMapper.selectById(blog.getTypeId());
        if (type == null)
            throw new MyException(400, "参数错误：type_id不存在：" + blog.getTypeId());
        // 2.2修改
        int i = blogMapper.updateById(blog);
        if (i != 1)
            throw new MyException(500, "更新失败，可能是id不存在：" + blog.getId());

        // 3.对于标签和博客对应关系的修改
        // 3.1 检查tag的id是否正确
        List<Integer> tagIdList = new LinkedList<>();
        for (String t : tag)
            tagIdList.add(Integer.parseInt(t));

        List<Tag> tags = tagMapper.selectBatchIds(tagIdList);//这里的tagList不能为空的哦，否则报错
        if (tags.size() != tag.length)
            throw new MyException(400, "参数错误，tag存在非法id：" + Arrays.toString(tag));
        // 3.2 查出原有的tagIdList
        List<Integer> old_tagIdList = blogTagReferenceMapper.getTagIdListByBlogId(blog.getId());
        for (int id : tagIdList) {
            if (old_tagIdList.contains(id)) //如果有，则移除
                old_tagIdList.remove(Integer.valueOf(id));
            else {//如果没有，则插入关联
                BlogTagReference reference = new BlogTagReference();
                reference.setBlogId(blog.getId());
                reference.setTagId(id);
                reference.setFlag(0);
                reference.setCreateBy(loginId);
                reference.setEditBy(loginId);
                // 3.3 插入新关联
                if ((blogTagReferenceMapper.insert(reference)) != 1)
                    throw new MyException(500, "插入blog和tag的关联失败");
            }
        }
        // 3.4 删除的不再标记的标签与博客的关联
        for (int tagId : old_tagIdList) {
            if ((blogTagReferenceMapper.logicalDeleteByBlogIdTagId(blog.getId(), tagId, loginId)) != 1)
                throw new MyException(500, "删除blog和tag的关联失败");
        }
        // 4.删除redis key:blogInfo:id:xx
        redisService.delete("blogInfo:id:" + blog.getId());
    }

    /**
     * 1.删除blog
     * 2.blog和tag的关联
     * 3.删评论？当前选择不删除
     *
     * @param id      博客id
     * @param loginId 登录id
     * @return 返回msg作为提示
     */
    @Override
    @Transactional//开事务
    public String deleteBlog(int id, int loginId) {
        // 1.删除blog
        if (1 != blogMapper.logicalDelete(id, loginId))
            throw new MyException(400, "删除博客失败，可能是id错误：" + id);

        // 2.删除关联
        int r = blogTagReferenceMapper.realDeleteByBlogId(id);
        String msg = "删除成功，删除标签关联 " + r + " 个";

        // 3.删除评论？？？选择不删除
        msg += "; 没有级联删除评论";

        // 4.删除redis key：blogInfo:id:xx
        redisService.delete("blogInfo:id:" + id);
        return msg;
    }

    @Override
    public String getBlogContent(int id) {
        String content = blogMapper.getBlogContent(id);
        if (content == null)
            throw new MyException(400, "博客id不存在：" + id);
        return content;
    }

    @Override
    public Map<String, Object> getBlogInfoPage(String title, Integer typeId, Integer userId, Integer[] tag, Boolean published, Integer flag, int index, int pageSize) {
        // 1.先分页查询
        List<BlogInfo> result = new LinkedList<>();
        // 1.1取得total
        int total = blogMapper.getBlogIdList(title, typeId, userId, tag, published, flag).size();
        // 1.2 取得blogInfoList
        List<BlogInfo> blogInfos = blogMapper.getBlogInfoPage(title, typeId, userId, tag, published, flag, index, pageSize);

        // 2.将blogInfo信息完善
        for (BlogInfo blogInfo : blogInfos) {
            // 2.1 完善tagList
            List<Tag> tagList = tagMapper.getTagListByBlogId(blogInfo.getId());
            blogInfo.setTagList(tagList);
            // 2.2 完善创建人信息
            User user = userMapper.selectById(blogInfo.getCreateBy());
            blogInfo.setCreateUser(user);
        }
        // 3.放入map
        Map<String, Object> map = new HashMap<>();
        map.put("total", total);
        map.put("data", blogInfos);
        return map;
    }

    @Override
    @Transactional//开启事务
    public int increaseViewTimes(int blogId) {
        if (blogMapper.increaseViewTimes(blogId) != 1) {
            throw new MyException(500, "更新观看次数失败，id：" + blogId);
        }
        return blogMapper.getViewTimesById(blogId);
    }

    @Override
    @Transactional//开启事务
    public void recycleBlog(int id, int loginId) {
        if (1 != blogMapper.recycleBlog(id, loginId))
            throw new MyException(500, "更新失败，可能是id无效：" + id + " ；也可能是此博客不在回收站");
    }

    @Override
    public Map<String, Object> getNewBlogInfoList() {
        // 1. 先去redis 拿
        String newBlogList_json = redisService.get("newBlogList");
        if (newBlogList_json == null) {
            // 2.为空去数据库获取
            List<BlogInfo> blogInfoList = blogMapper.getNewBlogInfoList();
            try {
                newBlogList_json = MyJsonUtil.writeToString(blogInfoList);
                // 2.2 存入redis
                redisService.setEx("newBlogList", newBlogList_json);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        // 3.返回
        return ResponseResult.success("查询成功", newBlogList_json);
    }

    @Override
    public List<BlogInfo> getBlogInfoList(String title, String username, Integer typeId, List<Integer> tag, Boolean published, Integer flag) {
        List<BlogInfo> result = new LinkedList<>();
        // 1.先根据其他几个条件查：非tag
        List<BlogInfo> blogInfos = blogMapper.getBlogInfoList(title, username, typeId, published, flag);

        // 2.查询tagList进行赋值
        for (BlogInfo blogInfo : blogInfos) {
            List<Tag> tagListByBlogId = tagMapper.getTagListByBlogId(blogInfo.getId());
            if (tagListByBlogId.size() < tag.size())
                continue;
            boolean blog_flag = true;//true为符合
            for (int tagId : tag) {
                boolean tagId_flag = false;//false为没找到
                for (Tag t : tagListByBlogId) {
                    if (t.getId() == tagId) {
                        tagId_flag = true;//true为找到
                        break;
                    }
                }
                if (!tagId_flag) {// 如果没有找到
                    blog_flag = false;
                    break;
                }
            }
            // 3.每次检查tag是否符合筛选条件
            if (blog_flag) {// 如果tag符合要求
                blogInfo.setTagList(tagListByBlogId);
                // 4.再将user查询出来
                User user = userMapper.selectById(blogInfo.getCreateBy());
                blogInfo.setCreateUser(user);
                result.add(blogInfo);
            }
        }
        return result;
    }

    @Override
    public BlogInfo getBlogInfoById(int id, boolean published) throws JsonProcessingException {
        BlogInfo blogInfo = null;
        // 1.先去redis查
        String json = redisService.get("blogInfo:id:" + id);
        // 2.如果没有，则数据库查，并放入redis
        if (json != null)
            blogInfo = MyJsonUtil.toBean(json, BlogInfo.class);
        else {
            // 2.1查询blogInfo
            blogInfo = blogMapper.getBlogInfoById(id);
            if (blogInfo == null)
                throw new MyException(400, "参数错误：id不存在：" + id);
            if (blogInfo.getPublished() != published)
                throw new MyException(400, "参数错误：published：" + published);
            // 2.2.查content
            blogInfo.setContent(blogMapper.getBlogContent(id));
            // 2.3.查出tagList
            blogInfo.setTagList(tagMapper.getTagListByBlogId(blogInfo.getId()));
            // 2.4.查出user
            blogInfo.setCreateUser(userMapper.selectById(blogInfo.getCreateBy()));
            // 2.5 放入redis
            redisService.setEx("blogInfo:id:" + id, MyJsonUtil.writeToString(blogInfo));
        }

        return blogInfo;
    }

}
